package com.penghu.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;

import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

public class PengHuOpenApiUtils implements AutoCloseable {
    private static final String BASE_URL = "http://openapi.spaceiot.com.cn";
    private static final PoolingHttpClientConnectionManager CONNECTION_MANAGER;
    private static final RequestConfig REQUEST_CONFIG;
    private final CloseableHttpClient httpClient;
    private String account;
    private String key;

    static {
        // 初始化连接池
        CONNECTION_MANAGER = new PoolingHttpClientConnectionManager();
        CONNECTION_MANAGER.setMaxTotal(200);
        CONNECTION_MANAGER.setDefaultMaxPerRoute(50);

        // 配置请求参数
        REQUEST_CONFIG = RequestConfig.custom()
                .setConnectTimeout(5000)
                .setSocketTimeout(10000)
                .setConnectionRequestTimeout(2000)
                .build();
    }
    //HTTP客户端复用，避免每次创建/销毁HTTP客户端，减少TCP连接开销
    public PengHuOpenApiUtils() {
        this.httpClient = createHttpClient();
    }

    private CloseableHttpClient createHttpClient() {
        return HttpClientBuilder.create()
                .setConnectionManager(CONNECTION_MANAGER)
                .setDefaultRequestConfig(REQUEST_CONFIG)
                .evictExpiredConnections()
                .evictIdleConnections(30, TimeUnit.SECONDS)
                .disableCookieManagement()
                .build();
    }

    /**
     * 账号初始化
     * @param account 开放平台账户
     * @param key 开放平台密码
     */
    public void init(String account, String key) {
        this.account = Objects.requireNonNull(account, "账号不能为空");
        this.key = Objects.requireNonNull(key, "密码不能为空");
    }

    /**
     * 获取终端列表
     * @param page: 页数
     * @param size: 每页个数
     */
    public ResultList getTerminalList(int page, int size) {
        return executePaginatedQuery("/terminal/findPage", page, size, null);
    }

    /**
     * 获取传感器列表
     * @param page：页数
     * @param size：每页个数
     */
    public ResultList getSensorList(int page, int size) {
        return executePaginatedQuery("/sensor/findPage", page, size, null);
    }


    /**
     * 实时报文
     * @param startDate：开始时间（UTC时间戳）
     * @param page：页数
     * @param size：每页个数
     */
    public ResultList getRealTimeMessageList(Long startDate, int page, int size){
        JSONObject params = new JSONObject();
        params.put("startDate", startDate);
        return executePaginatedQuery("/realtimemessage/findPage", page, size, params);
    }

    /**
     * 透传报文
     * @param startDate：开始时间（UTC时间戳）
     * @param page：页数
     * @param size：每页个数
     */
    public ResultList getMessageList(Long startDate, int page, int size) {
        JSONObject params = new JSONObject();
        params.put("startDate", startDate);
        return executePaginatedQuery("/message/findPage", page, size, params);
    }

    /**
     * 消息报文
     * @param startDate：开始时间（UTC时间戳）
     * @param page：页数
     * @param size：每页个数
     */
    public ResultList getImMessageList(Long startDate, int page, int size){
        JSONObject params = new JSONObject();
        params.put("startDate", startDate);
        return executePaginatedQuery("/im/message/findPage", page, size, params);
    }


    /**
     * 解析报文（SAT）
     * @param startDate：开始时间（UTC时间戳）
     * @param page：页数
     * @param size：每页个数
     */
    public ResultList getSATMessageList(Long startDate, Integer page, Integer size) {
        JSONObject params = new JSONObject();
        params.put("startDate", startDate);
        return executePaginatedQuery("/sat/message/findPage", page, size, params);
    }

    /**
     * 解析报文（NB）
     * @param startDate：开始时间（UTC时间戳）
     * @param page：页数
     * @param size：每页个数
     */
    public ResultList getNBMessageList(Long startDate, Integer page, Integer size) {
        JSONObject params = new JSONObject();
        params.put("startDate", startDate);
        return executePaginatedQuery("/nb/message/findPage", page, size, params);
    }

    /**
     * 最新报文（单条）
     * @param type     报文类型（0：原始报文，1：业务报文）
     * @param terminalId 设备号（选填）
     * @param sn sn号（选填）
     * @param sin      业务类型（选填，0：原始报文，128：业务报文）
     */
    public Result getLatestMessage(int type, String terminalId, String sn,Integer sin) {
        String url = BASE_URL + "/message/findNewFirst";
        JSONObject params = new JSONObject();
        params.put("type", type);
        if (terminalId != null && !terminalId.isEmpty()) {
            params.put("terminalId", terminalId);
        }
        if(sn != null && !sn.isEmpty()){
            params.put("sn", sn);
        }
        if (sin != null) {
            params.put("sin", sin);
        }

        String result = sendRequest(url, params.toJSONString());
        JSONObject json = JSON.parseObject(result);
        return new Result().success(json.get("data"));
    }

    /**
     * 发送Ping指令（下行指令）
     * @param terminalId：终端编号
     * @param sn：sn号
     */
    public Result sendPing(String terminalId,String sn) {
        return executeCommand("/scheme/task/sendPing", terminalId, sn,null);
    }


    /**
     * 重启指令（下行指令）
     * @param terminalId：终端编号
     * @param sn：sn号
     */
    public Result reStart(String terminalId,String sn) {
        return executeCommand("/scheme/task/reStart", terminalId,sn, null);
    }

    /**
     * 获取位置（下行指令）
     * @param terminalId：终端编号
     * @param sn：sn号
     */
    public Result getLocation(String terminalId,String sn) {
        return executeCommand("/scheme/task/getLocation", terminalId,sn, null);
    }

    /**
     * 自定义数据（下行指令）
     * @param terminalId：终端编号
     * @param sn：sn号
     * @param taskExt：数据内容
     */
    public Result sendTask(String terminalId,String sn ,String taskExt) {
        JSONObject params = new JSONObject();
        if (terminalId != null && !terminalId.isEmpty()) {
            params.put("terminalId", terminalId);
        }
        if(sn != null && !sn.isEmpty()){
            params.put("sn", sn);
        }
        params.put("taskExt", taskExt);
        return executeCommand("/scheme/task/sendTask", params);
    }

    /**
     * 查询下行指令状态
     * @param taskId: 任务ID(发送下行指令返回的)
     */
    public Result getTaskResult(String taskId) {
        JSONObject params = new JSONObject();
        params.put("taskId", taskId);
        return executeCommand("/scheme/task/findTaskResult", params);
    }

    /**
     * 流量查询
     * @param terminalId：终端编号
     * @param sn：sn号
     * @param startDate：开始时间（时间戳）
     * @param endDate：结束时间（时间戳）
     */
    public ResultList getFlowByTerminal(String terminalId,String sn, Long startDate, Long endDate) {
        JSONObject params = new JSONObject();
        if (terminalId != null && !terminalId.isEmpty()) {
            params.put("terminalId", terminalId);
        }
        if(sn != null && !sn.isEmpty()){
            params.put("sn", sn);
        }
        params.put("startDate", startDate);
        params.put("endDate", endDate);
        return executePaginatedQuery("/flowstatistics/findByTerminal", 0, 0, params);
    }


    /**
     * 统一处理分页查询
     * */
    private ResultList executePaginatedQuery(String endpoint, int page, int size, JSONObject extraParams) {
        JSONObject params = new JSONObject();
        if (page > 0) {
            params.put("page", page);
        }
        if (size > 0) {
            params.put("size", size);
        }
        if (extraParams != null) {
            params.putAll(extraParams);
        }
        String url = BASE_URL + endpoint;
        String result = sendRequest(url, params.toJSONString());
        JSONObject json = JSON.parseObject(result);
        return new ResultList().success(json.get("data"), json.getIntValue("total"));
    }

    /**
     * 统一所有操作指令
     * */
    private Result executeCommand(String endpoint, String terminalId, String sn,JSONObject extraParams) {
        JSONObject params = new JSONObject();

        if (terminalId != null && !terminalId.isEmpty()) {
            params.put("terminalId", terminalId);
        }
        if(sn != null && !sn.isEmpty()){
            params.put("sn", sn);
        }
        if (extraParams != null) {
            params.putAll(extraParams);
        }
        return executeCommand(endpoint, params);
    }

    private Result executeCommand(String endpoint, JSONObject params) {
        String url = BASE_URL + endpoint;
        String result = sendRequest(url, params.toJSONString());
        JSONObject json = JSON.parseObject(result);
        return new Result().success("提交成功", json.get("data"));
    }

    /**
     * 发送API请求
     * @param url : 请求路径
     * @param requestBody: 请求参数 json格式
     */
    public String sendRequest(String url, String requestBody) {
        long l = System.currentTimeMillis();
        if (account == null || key == null) {
            throw new IllegalStateException("账号和密码未初始化");
        }
        try {
            // 加密和编码
            String encryptedBody = SM4Utils.encrypt(key, requestBody);
            String body = Base64.encodeBase64String(encryptedBody.getBytes(StandardCharsets.UTF_8));
            // 构建JSON请求体
            JSONObject requestJson = new JSONObject();
            requestJson.put("requestBody", body);

            HttpPost httpPost = new HttpPost(url);
            httpPost.setHeader("SpaceIOT_Account", account);
            httpPost.setHeader("Content-Type", "application/json");
            httpPost.setEntity(new StringEntity(requestJson.toString(), StandardCharsets.UTF_8));

            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
                int statusCode = response.getStatusLine().getStatusCode();
                String responseBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
                if (statusCode == 200) {
                    return responseBody;
                } else {
                    return String.format("{\"status\":\"error\",\"code\":%d,\"message\":\"%s\"}",
                            statusCode, responseBody);
                }
            }
        } catch (Exception e) {
            return String.format("{\"status\":\"exception\",\"message\":\"%s\"}", e.getMessage());
        }
    }
    @Override
    public void close() throws Exception {
        if (httpClient != null) {
            httpClient.close();
        }
    }
}